﻿using System;
using System.ComponentModel;
using System.Windows.Threading;
using System.Diagnostics;
using Infrastructure.CurrentData;
using log4net;
using Microsoft.Practices.Composite.Events;

namespace Infrastructure.ViewModels
{
    /// <summary>
    /// Data model general implementation
    /// </summary>
    public class DataModel : INotifyPropertyChanged
    {
        protected ILog Log;

        /// <summary>
        /// The dispatcher
        /// </summary>
        Dispatcher _dispatcher;
        /// <summary>
        /// The model state
        /// </summary>
        ModelState state;
        /// <summary>
        /// Property changed event
        /// </summary>
        PropertyChangedEventHandler _propertyChangedEvent;

        /// <summary>
        /// Gets or sets the event aggregator.
        /// </summary>
        /// <value>The event aggregator.</value>
        protected IEventAggregator EventAggregator { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="DataModel"/> class.
        /// </summary>
        public DataModel()
        {
            EventAggregator = Current.Container.Resolve<IEventAggregator>();

            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DataModel"/> class.
        /// </summary>
        public DataModel(IEventAggregator eventAggregator)
        {
            EventAggregator = eventAggregator;

            Initialize();
        }

        void Initialize()
        {
            Log = Current.Container.Resolve<ILog>();
            _dispatcher = Dispatcher.CurrentDispatcher;
        }

        

        /// <summary>
        /// Gets or sets the dispatcher.
        /// </summary>
        /// <value>The dispatcher.</value>
        public Dispatcher Dispatcher
        {
            get
            {
                VerifyCalledOnUIThread();
                return _dispatcher;
            }
            protected set
            {
                VerifyCalledOnUIThread();
                _dispatcher = value;
            }
        }

        /// <summary>
        /// Gets or sets the state of the data model.
        /// </summary>
        /// <value>The state.</value>
        public ModelState State
        {
            get
            {
                VerifyCalledOnUIThread();
                return state;
            }
            protected set
            {
                VerifyCalledOnUIThread();
                if (value != state)
                {
                    state = value;
                    OnPropertyChanged("State");
                }
            }
        }

        /// <summary>
        /// Called when [property changed].
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        protected void OnPropertyChanged(string propertyName)
        {
            VerifyCalledOnUIThread();
            if (_propertyChangedEvent != null)
            {
                _propertyChangedEvent(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        /// <summary>
        /// Verifies that the caller is on the UI thread.
        /// </summary>
        [Conditional("Debug")]
        protected void VerifyCalledOnUIThread()
        {
            Debug.Assert(Dispatcher.CurrentDispatcher == _dispatcher, "Call must be made on UI thread.");
        }

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Occurs when a property value changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged
        {
            add
            {
                VerifyCalledOnUIThread();
                _propertyChangedEvent += value;
            }
            remove
            {
                VerifyCalledOnUIThread();
                _propertyChangedEvent -= value;
            }
        }

        #endregion

        /// <summary>
        /// Occurs when [loaded].
        /// </summary>
        public virtual event EventHandler<EventArgs> Loaded;

        /// <summary>
        /// Called when [loaded].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void OnLoaded(object sender, EventArgs e)
        {
            if (Loaded != null)
            {
                Loaded(sender, e);
            }
        }
    }
}